import SwiftUI

class FCUIView: NSView, NSTextFieldDelegate{
    var m_paint = FCPaint()
    var m_isInit = false
    var m_textBox = NSTextField()
    var m_editingTextBox = FCTextBox()
    var m_initTextBox : Bool = false
    
    /*
     * 鼠标按下方法
     * view:视图
     * mp:坐标
     * buttons:按钮
     * clicks:点击次数
     * delta:滚轮值
     */
    func onMouseDown(view:FCView, mp:FCPoint, buttons:Int, clicks:Int, delta:Int)
    {
        onMouseDownDefault(view: view, mp: mp, buttons: buttons, clicks: clicks, delta: delta)
    }
    
    /*
     * 鼠标移动方法
     * view:视图
     * mp:坐标
     * buttons:按钮
     * clicks:点击次数
     * delta:滚轮值
     */
    func onMouseMove(view:FCView, mp:FCPoint, buttons:Int, clicks:Int, delta:Int)
    {
        onMouseMoveDefault(view: view, mp: mp, buttons: buttons, clicks: clicks, delta: delta)
    }
    
    /*
     * 鼠标抬起方法
     * view:视图
     * mp:坐标
     * buttons:按钮
     * clicks:点击次数
     * delta:滚轮值
     */
    func onMouseUp(view:FCView, mp:FCPoint, buttons:Int, clicks:Int, delta:Int)
    {
        onMouseUpDefault(view: view, mp: mp, buttons: buttons, clicks: clicks, delta: delta)
    }
    
    /*
     * 鼠标滚轮方法
     * view:视图
     * mp:坐标
     * buttons:按钮
     * clicks:点击次数
     * delta:滚轮值
     */
    func onMouseWheel(view:FCView, mp:FCPoint, buttons:Int, clicks:Int, delta:Int)
    {
        onMouseWheelDefault(view: view, mp: mp, buttons: buttons, clicks: clicks, delta: delta)
    }
    
    /*
     * 键盘按下方法
     * view:视图
     * value:键盘值
     */
    func onKeyDown(view:FCView, value:Int)
    {
        onKeyDownDefault(view: view, value: value)
    }
    
    /*
     * 键盘抬起方法
     * view:视图
     * value:键盘值
     */
    func onKeyUp(view:FCView, value:Int)
    {
        onKeyUpDefault(view: view, value: value)
    }

    /*
    * 点击方法
    * view:视图
    * firstTouch:是否第一次触摸
    * firstPoint:第一次触摸的坐标
    * secondTouch:是否第二次触摸
    * secondPoint:第二次触摸的坐标
    * clcks:点击次数
    */
    func onClick(view:FCView, firstTouch:Bool, firstPoint:FCPoint, secondTouch:Bool, secondPoint:FCPoint, clicks:Int) {
        onClickDefault(view:view, firstTouch:firstTouch, firstPoint:firstPoint, secondTouch:secondTouch, secondPoint:secondPoint, clicks: clicks)
    }

    /*
    * 重绘背景的实现方法
    * view:视图
    * paint:绘图对象
    * clipRect:裁剪区域
    */
    func onPaint(view:FCView, paint:FCPaint, clipRect:FCRect) {
        onPaintDefault(view:view, paint:paint, clipRect:clipRect)
    }

    /*
    * 重绘边框的实现方法
    * view:视图
    * paint:绘图对象
    * clipRect:裁剪区域
    */
    func onPaintBorder(view:FCView, paint:FCPaint, clipRect:FCRect) {
        onPaintBorderDefault(view:view, paint:paint, clipRect:clipRect)
    }
    
    /*
    * 更新悬浮状态
    * views:视图集合
    */
    func updateView(views:[FCView]) {
        updateViewDefault(views: views)
    }
    
    /*
     * 初始化布局
     */
    func onLoad(){
        if !self.m_isInit{
            m_editingTextBox.isNotEmpty = false
            self.m_isInit = true
            m_paint.setUIView(view: self)
            m_paint.addUpdateViewEvent(callBack: updateView)
            m_paint.addPaintEvent(callBack: onPaint)
            m_paint.addPaintBorderEvent(callBack: onPaintBorder)
            m_paint.addClickEvent(callBack: onClick)
            m_paint.addMouseDownEvent(callBack: onMouseDown)
            m_paint.addMouseMoveEvent(callBack: onMouseMove)
            m_paint.addMouseUpEvent(callBack: onMouseUp)
            m_paint.addMouseWheelEvent(callBack: onMouseWheel)
            m_paint.addKeyDownEvent(callBack: onKeyDown)
            m_paint.addKeyUpEvent(callBack: onKeyUp)
            //renderFaceCat(paint: m_paint, size: FCSize(cx:width, cy:height))
            self.perform(#selector(self.onTimer), with: "", afterDelay: 0.01)
            let area = NSTrackingArea.init(rect: self.bounds, options: [.mouseMoved,.activeAlways,.inVisibleRect], owner: self, userInfo: nil)
            self.addTrackingArea(area)
        }
    }
    
    @objc func onTimer(){
        updateScroll(views: m_paint.views)
        self.perform(#selector(self.onTimer), with: "", afterDelay: 0.01)
    }
    
    override func draw(_ rect: CGRect) {
        onLoad()
        m_paint.wHeight = self.frame.size.height
        if m_paint.size.cx != self.frame.size.width || m_paint.size.cy != self.frame.size.height{
            m_paint.size = FCSize(cx:self.frame.size.width, cy:self.frame.size.height);
            updateView(views: self.m_paint.views)
        }
        let cRect = CGRect(x: rect.origin.x, y: m_paint.wHeight - rect.origin.y - rect.height, width: rect.width, height: rect.height)
        let drawRect = FCRect(left: cRect.origin.x / m_paint.scaleFactorX, top: cRect.origin.y / m_paint.scaleFactorY, right: (cRect.origin.x + cRect.width) / m_paint.scaleFactorX, bottom:(cRect.origin.y + cRect.height) / m_paint.scaleFactorY)
        m_paint.beginPaint(rect: drawRect)
        renderViews(views: self.m_paint.views, paint: self.m_paint, rect: drawRect)
        m_paint.endPaint()
    }
    
    /*
     * 显示文本框
     */
    func showTextBox(textBox:FCTextBox, lastView:FCView){
        if m_initTextBox{
            if lastView.isNotEmpty && lastView != textBox && lastView.viewType == "textbox"{
                lastView.text = m_textBox.stringValue
                invalidateView(view: lastView)
            }
        }
        m_editingTextBox = textBox
        let scaleFX = m_paint.scaleFactorX
        let scaleFY = m_paint.scaleFactorY
        let clx = clientX(view: textBox)
        let cly = clientY(view: textBox)
        let x = (clx * scaleFX) + 1
        let y = (cly * scaleFY) + 1
        let cx = (textBox.size.cx - 2) * scaleFX
        let cy = (textBox.size.cy - 2) * scaleFY
        let rect  = CGRect(x:x, y: self.frame.size.height - y - cy, width: cx, height: cy)
        if !m_initTextBox{
            m_textBox = NSTextField()
            m_initTextBox = true
        }
        m_textBox.stringValue = textBox.text
        m_textBox.backgroundColor = stringToColor(str: textBox.backColor)
        m_textBox.textColor = stringToColor(str: textBox.textColor)
        let strs = textBox.font.split(separator: ",")
        var fontName = String(strs[0])
        if fontName == "Default"{
            fontName = m_paint.systemFont
        }
        var fontSize = StringToFloat(str: String(strs[1]))
        fontSize = CGFloat(min(m_paint.scaleFactorX, m_paint.scaleFactorY)) * fontSize
        m_textBox.font = NSFont(name: fontName, size: fontSize)
        self.addSubview(m_textBox)
        m_textBox.becomeFirstResponder()
        m_textBox.frame = rect
        m_textBox.delegate = self
    }
    
    /*
     * 隐藏文本框
     */
    func hideTextBox(textBox:FCTextBox){
        m_editingTextBox.text = m_textBox.stringValue
        m_textBox.removeFromSuperview()
        invalidateView(view: textBox)
        m_editingTextBox = FCTextBox()
        m_editingTextBox.isNotEmpty = false
    }
    
    /*
     * 鼠标点击事件
     * paint 绘图对象
     * mp 坐标
     * buttons 按钮
     * clicks 点击次数
     * delta 滚轮值
     */
    func handleMouseDown(paint:FCPaint, mp:FCPoint, buttons:Int, clicks:Int, delta:Int) {
        paint.cancelClick = false
        paint.touchDownPoint = FCPoint(x:mp.x, y:mp.y)
        paint.touchDownView = [FCView]()
        if clicks == 2{
            paint.isDoubleClick = true
        }else{
            paint.isDoubleClick = false
        }
        let lastFocusedView = paint.getFocusedView()
        let fView = findView(mp:mp, views:paint.views)
        if fView.isNotEmpty{
            paint.setTouchDownView(view:fView)
            checkShowMenu(paint:paint)
            paint.setFocusedView(view:paint.getTouchDownView())
            let clx = clientX(view:paint.getTouchDownView())
            let cly = clientY(view:paint.getTouchDownView())
            let cmp = FCPoint(x:mp.x, y:mp.y)
            cmp.x -= clx
            cmp.y -= cly
            if paint.hasMouseDownEvent{
                paint.onMouseDown(paint.getFocusedView(), cmp, buttons, clicks, delta)
            }else{
                onMouseDownDefault(view: paint.getFocusedView(), mp:cmp, buttons: buttons, clicks: clicks, delta: delta)
            }
            if fView.viewType == "textbox"{
                showTextBox(textBox: fView as! FCTextBox, lastView: lastFocusedView)
            }else{
                if(m_editingTextBox.isNotEmpty){
                    hideTextBox(textBox: m_editingTextBox)
                }
            }
            if(fView.allowResize){
                fView.resizePoint = getResizeState(view:fView, mp:cmp)
                if fView.resizePoint != -1{
                    fView.startRect = FCRect(left:fView.location.x, top:fView.location.y, right:fView.location.x + fView.size.cx, bottom:fView.location.y + fView.size.cy)
                }
            }
        }
    }

    /*
     * 鼠标移动事件
     * paint 绘图对象
     * mp 坐标
     * buttons 按钮
     * clicks 点击次数
     * delta 滚轮值
     */
    func handleMouseMove(paint:FCPaint, mp:FCPoint, buttons:Int, clicks:Int, delta:Int) {
        if paint.getTouchDownView().isNotEmpty {
            let mDownView = paint.getTouchDownView()
            let clx = clientX(view:mDownView)
            let cly = clientY(view:mDownView)
            let cmp = FCPoint(x:mp.x, y:mp.y)
            cmp.x -= clx
            cmp.y -= cly
            if paint.hasMouseMoveEvent{
                paint.onMouseMove(mDownView, cmp, buttons, clicks, delta)
            }else{
                onMouseMoveDefault(view: mDownView, mp: cmp, buttons: buttons, clicks: clicks, delta: delta)
            }
            if mDownView.resizePoint != -1{
                let newBounds = FCRect(left:mDownView.startRect.left, top:mDownView.startRect.top, right:mDownView.startRect.right, bottom:mDownView.startRect.bottom)
                windowResize(rect:newBounds, resizePoint:mDownView.resizePoint, nowPoint:mp, startTouchPoint:paint.touchDownPoint)
                mDownView.location = FCPoint(x:newBounds.left, y:newBounds.top)
                mDownView.size = FCSize(cx:newBounds.right - newBounds.left, cy:newBounds.bottom - newBounds.top)
                if mDownView.getParent().isNotEmpty {
                    invalidateView(view:mDownView.getParent())
                } else {
                    invalidate(paint:paint)
                }
            }
            else if mDownView.allowDrag {
                if (abs(mp.x - paint.touchDownPoint.x) > 5 || abs(mp.y - paint.touchDownPoint.y) > 5) {
                    paint.dragBeginRect = FCRect(left:mDownView.location.x, top:mDownView.location.y,
                                                 right:mDownView.location.x + mDownView.size.cx,
                                                 bottom:mDownView.location.y + mDownView.size.cy)
                    paint.dragBeginPoint = FCPoint(x:paint.touchDownPoint.x, y:paint.touchDownPoint.y)
                    paint.setDraggingView(view:mDownView)
                    paint.touchDownView = [FCView]()
                }
            }
        }
        else if paint.getDraggingView().isNotEmpty {
            let offsetX = mp.x - paint.dragBeginPoint.x
            let offsetY = mp.y - paint.dragBeginPoint.y
            let newBounds = FCRect(left:paint.dragBeginRect.left + offsetX, top:paint.dragBeginRect.top + offsetY,
                                   right:paint.dragBeginRect.right + offsetX, bottom:paint.dragBeginRect.bottom + offsetY)
            let dView = paint.getDraggingView()
            dView.location = FCPoint(x:newBounds.left, y:newBounds.top)
            if (paint.getDraggingView().getParent().isNotEmpty && paint.getDraggingView().getParent().viewType == "split") {
                resetSplitLayoutDiv(split:paint.getDraggingView().getParent() as! FCSplitLayoutDiv);
                if (paint.hasUpdateViewEvent) {
                    paint.onUpdateView(paint.views);
                  } else {
                    updateViewDefault(views:paint.views);
                  }
            }
            if dView.getParent().isNotEmpty {
                invalidateView(view:dView.getParent())
            } else {
                invalidate(paint:paint)
            }
        }else{
            let view = findView(mp:mp, views:paint.views)
            if view.isNotEmpty{
                let clx = clientX(view:view)
                let cly = clientY(view:view)
                let cmp = FCPoint(x:mp.x, y:mp.y)
                cmp.x -= clx
                cmp.y -= cly
                let oldMouseMoveView = paint.getTouchMoveView()
                paint.setTouchMoveView(view: view)
                if oldMouseMoveView.isNotEmpty && oldMouseMoveView != view{
                    if paint.hasMouseLeaveEvent{
                        paint.onMouseLeave(oldMouseMoveView, cmp, buttons, clicks, 0)
                    }
                    invalidateView(view:oldMouseMoveView)
                }
                if !oldMouseMoveView.isNotEmpty || oldMouseMoveView != view{
                    if paint.hasMouseEnterEvent{
                        paint.onMouseEnter(view, cmp, buttons, clicks, 0)
                    }
                    if view.cursor == "closedhand"{
                        NSCursor.closedHand.set()
                    }
                    else if view.cursor == "cross"{
                        NSCursor.crosshair.set()
                    }
                    else if view.cursor == "disappearingitem"{
                        NSCursor.disappearingItem.set()
                    }
                    else if view.cursor == "dragcopy"{
                        NSCursor.dragCopy.set()
                    }
                    else if view.cursor == "draglink"{
                        NSCursor.dragLink.set()
                    }
                    else if view.cursor == "hand"{
                        NSCursor.openHand.set()
                    }
                    else if view.cursor == "ibeam"{
                        NSCursor.iBeam.set()
                    }
                    else if view.cursor == "ibeamcursorforverticalLayout"{
                        NSCursor.iBeamCursorForVerticalLayout.set()
                    }
                    else if view.cursor == "no"{
                        NSCursor.operationNotAllowed.set()
                    }
                    else if view.cursor == "pointinghand"{
                        NSCursor.pointingHand.set()
                    }
                    else if view.cursor == "sizedown"{
                        NSCursor.resizeDown.set()
                    }
                    else if view.cursor == "sizeleft"{
                        NSCursor.resizeLeft.set()
                    }
                    else if view.cursor == "sizeright"{
                        NSCursor.resizeRight.set()
                    }
                    else if view.cursor == "sizeup"{
                        NSCursor.resizeUp.set()
                    }
                    else if view.cursor == "sizewe"{
                        NSCursor.resizeLeftRight.set()
                    }
                    else if view.cursor == "sizens"{
                        NSCursor.resizeUpDown.set()
                    }
                    else{
                        NSCursor.arrow.set()
                    }
                }
                if paint.hasMouseMoveEvent{
                    paint.onMouseMove(view, cmp, buttons, clicks, 0)
                }
                else{
                    onMouseMoveDefault(view:view, mp:cmp, buttons:buttons, clicks:clicks, delta:delta)
                }
            }
        }
    }

    /*
     * 鼠标抬起事件
     * paint 绘图对象
     * mp 坐标
     * buttons 按钮
     * clicks 点击次数
     * delta 滚轮值
     */
    func handleMouseUp(paint:FCPaint, mp:FCPoint, buttons:Int, clicks:Int, delta:Int) {
        if paint.getTouchDownView().isNotEmpty {
            let mDownView = paint.getTouchDownView()
            let clx = clientX(view:mDownView)
            let cly = clientY(view:mDownView)
            let cmp = FCPoint(x:mp.x, y:mp.y)
            cmp.x -= clx
            cmp.y -= cly
            let view = findView(mp:mp, views:paint.views)
            if view.isNotEmpty && view == mDownView {
                if paint.hasClickEvent{
                    paint.onClick(view, true, cmp, false, cmp, 1)
                }else{
                    onClickDefault(view: view, firstTouch: true, firstPoint: cmp, secondTouch: false, secondPoint: cmp, clicks: 1)
                }
            }
            mDownView.resizePoint = -1;
            if paint.hasMouseUpEvent{
                paint.onMouseUp(mDownView, cmp, buttons, clicks, delta)
            }else{
                onMouseUpDefault(view: mDownView, mp: cmp, buttons: buttons, clicks: clicks, delta: delta)
            }
            paint.touchDownView = [FCView]()
        }
        paint.draggingView = [FCView]()
    }
    
    /*
     * 鼠标抬起事件
     * paint 绘图对象
     * mp 坐标
     * buttons 按钮
     * clicks 点击次数
     * delta 滚轮值
     */
    func handleMouseWheel(paint:FCPaint, mp:FCPoint, buttons:Int, clicks:Int, delta:Int) {
        let view = findView(mp:mp, views:paint.views)
        if view.isNotEmpty{
            let clx = clientX(view:view)
            let cly = clientY(view:view)
            let cmp = FCPoint(x:mp.x, y:mp.y)
            cmp.x -= clx
            cmp.y -= cly
            if paint.hasMouseWheelEvent{
                paint.onMouseWheel(view, cmp, buttons, clicks, delta)
            }
            else{
                onMouseWheelDefault(view:view, mp:cmp, buttons:buttons, clicks:clicks, delta:delta)
            }
        }
    }
    
    override func mouseDown(with event: NSEvent){
        var nsPoint = event.locationInWindow
        nsPoint.y = self.frame.size.height - nsPoint.y
        nsPoint.x /= m_paint.scaleFactorX
        nsPoint.y /= m_paint.scaleFactorY
        handleMouseDown(paint: self.m_paint, mp: FCPoint(x:nsPoint.x, y:nsPoint.y), buttons: 1, clicks: event.clickCount, delta: 0)
    }
    
    override func mouseUp(with event: NSEvent) {
        var nsPoint = event.locationInWindow
        nsPoint.y = self.frame.size.height - nsPoint.y
        nsPoint.x /= m_paint.scaleFactorX
        nsPoint.y /= m_paint.scaleFactorY
        handleMouseUp(paint: self.m_paint, mp: FCPoint(x:nsPoint.x, y:nsPoint.y), buttons: 1, clicks: event.clickCount, delta: 0)
    }
    
    override func mouseMoved(with event: NSEvent) {
        var nsPoint = event.locationInWindow
        nsPoint.y = self.frame.size.height - nsPoint.y
        nsPoint.x /= m_paint.scaleFactorX
        nsPoint.y /= m_paint.scaleFactorY
        handleMouseMove(paint: self.m_paint, mp: FCPoint(x:nsPoint.x, y:nsPoint.y), buttons: 0, clicks: 0, delta: 0)
    }
    
    override func mouseDragged(with event: NSEvent) {
        var nsPoint = event.locationInWindow
        nsPoint.y = self.frame.size.height - nsPoint.y
        nsPoint.x /= m_paint.scaleFactorX
        nsPoint.y /= m_paint.scaleFactorY
        handleMouseMove(paint: self.m_paint, mp: FCPoint(x:nsPoint.x, y:nsPoint.y), buttons: 1, clicks: event.clickCount, delta: 0)
    }
    
    override func scrollWheel(with event: NSEvent) {
        var nsPoint = event.locationInWindow
        nsPoint.y = self.frame.size.height - nsPoint.y
        nsPoint.x /= m_paint.scaleFactorX
        nsPoint.y /= m_paint.scaleFactorY
        handleMouseWheel(paint: self.m_paint, mp: FCPoint(x:nsPoint.x, y:nsPoint.y), buttons: 0, clicks: 0, delta: Int(event.scrollingDeltaY))
    }
    
    override func rightMouseDown(with event: NSEvent) {
        var nsPoint = event.locationInWindow
        nsPoint.y = self.frame.size.height - nsPoint.y
        nsPoint.x /= m_paint.scaleFactorX
        nsPoint.y /= m_paint.scaleFactorY
        handleMouseDown(paint: self.m_paint, mp: FCPoint(x:nsPoint.x, y:nsPoint.y), buttons: 2, clicks: event.clickCount, delta: 0)
    }
    
    override func rightMouseUp(with event: NSEvent) {
        var nsPoint = event.locationInWindow
        nsPoint.y = self.frame.size.height - nsPoint.y
        nsPoint.x /= m_paint.scaleFactorX
        nsPoint.y /= m_paint.scaleFactorY
        handleMouseUp(paint: self.m_paint, mp: FCPoint(x:nsPoint.x, y:nsPoint.y), buttons: 2, clicks: event.clickCount, delta: 0)
    }
    
    override func rightMouseDragged(with event: NSEvent) {
        var nsPoint = event.locationInWindow
        nsPoint.y = self.frame.size.height - nsPoint.y
        nsPoint.x /= m_paint.scaleFactorX
        nsPoint.y /= m_paint.scaleFactorY
        handleMouseMove(paint: self.m_paint, mp: FCPoint(x:nsPoint.x, y:nsPoint.y), buttons: 2, clicks: event.clickCount, delta: 0)
    }
}
